﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Mail;
using System.Text;
using Source.Common;


namespace Source.ServerSide
{
    public interface IEmailClientProcessor
    {
        void ProcessMail(string subject, string body, string fromEmailAddress, IEnumerable<string> toEmailAddresses, IEnumerable<string> ccEmailAddresses);
    }

    public class HtmlSmtpEmailClientProcessor : IEmailClientProcessor
    {

        private readonly IConfigurationProvider configurationProvider;

        public HtmlSmtpEmailClientProcessor(IConfigurationProvider configurationProvider)
        {
            this.configurationProvider = configurationProvider;
        }

        public void ProcessMail(string subject, string body, string fromEmailAddress, IEnumerable<string> toEmailAddresses, IEnumerable<string> ccEmailAddresses)
        {
            MailMessage mailMessage = CreateMessage(subject, body, fromEmailAddress, toEmailAddresses, ccEmailAddresses);
            SmtpClient smtpClient = CreateSmtpClient();

            smtpClient.Send(mailMessage);
        }

        private SmtpClient CreateSmtpClient()
        {
            SmtpClient smtpClient = new SmtpClient();
            smtpClient.Credentials = CreateNetworkCredentialsForSmtp();
            smtpClient.Host = configurationProvider.SmtpHost;

            return smtpClient;
        }

        private ICredentialsByHost CreateNetworkCredentialsForSmtp()
        {
            string userName = configurationProvider.SmtpUserName ?? "";
            string password = configurationProvider.SmtpPassword ?? "";
            string domain = configurationProvider.SmtpDomain ?? "";

            return new NetworkCredential(userName, password, domain);
        }

        public MailMessage CreateMessage(string subject, string body, string fromEmailAddress, IEnumerable<string> toEmailAddresses, IEnumerable<string> ccEmailAddresses)
        {
            MailMessage mailMessage = new MailMessage();

            mailMessage.IsBodyHtml = true;
            mailMessage.From = new MailAddress(fromEmailAddress);

            ValidateAddresses(toEmailAddresses, ccEmailAddresses);

            if (toEmailAddresses.Count() > 0)
            {
                mailMessage.To.Add(string.Join(", ", toEmailAddresses.ToArray()));
            }

            if (ccEmailAddresses.Count() > 0)
            {
                mailMessage.CC.Add(string.Join(", ", ccEmailAddresses.ToArray()));
            }

            mailMessage.Subject = subject;
            mailMessage.Body = body;

            return mailMessage;
        }

        private void ValidateAddresses(IEnumerable<string> toEmailAddresses, IEnumerable<string> ccEmailAddresses)
        {
            if (toEmailAddresses == null)
            {
                throw new ArgumentNullException("to");
            }

            if (ccEmailAddresses == null)
            {
                throw new ArgumentNullException("cc");
            }

            if (toEmailAddresses.Count() == 0 && ccEmailAddresses.Count() == 0)
            {
                throw new ArgumentException("There should be at least one TO or CC address.");
            }
        }
    }

    public class SingleAddressEmailClientProcessor : IEmailClientProcessor
    {

        private readonly IConfigurationProvider configurationProvider;

        public SingleAddressEmailClientProcessor(IConfigurationProvider configurationProvider)
        {
            this.configurationProvider = configurationProvider;
        }

        public void ProcessMail(string subject, string body, string fromEmailAddress, IEnumerable<string> toEmailAddresses, IEnumerable<string> ccEmailAddresses)
        {
            MailMessage mailMessage = CreateMessage(subject, body, fromEmailAddress, toEmailAddresses, ccEmailAddresses);
            SmtpClient smtpClient = CreateSmtpClient();

            smtpClient.Send(mailMessage);
        }

        private SmtpClient CreateSmtpClient()
        {
            SmtpClient smtpClient = new SmtpClient();
            smtpClient.Credentials = CreateNetworkCredentialsForSmtp();
            smtpClient.Host = configurationProvider.SmtpHost;

            return smtpClient;
        }

        private ICredentialsByHost CreateNetworkCredentialsForSmtp()
        {
            string userName = configurationProvider.SmtpUserName ?? "";
            string password = configurationProvider.SmtpPassword ?? "";
            string domain = configurationProvider.SmtpDomain ?? "";

            return new NetworkCredential(userName, password, domain);
        }

        public MailMessage CreateMessage(string subject, string body, string fromEmailAddress, IEnumerable<string> toEmailAddresses, IEnumerable<string> ccEmailAddresses)
        {
            MailMessage mailMessage = new MailMessage();

            mailMessage.IsBodyHtml = true;
            mailMessage.From = new MailAddress(fromEmailAddress);

            ValidateAddress(configurationProvider.DevelopmentEmailAddress);
            
            mailMessage.To.Add(configurationProvider.DevelopmentEmailAddress);
            mailMessage.Subject = "[DEV] " + subject;
            mailMessage.Body = CreateBody(subject, body, toEmailAddresses, ccEmailAddresses);

            return mailMessage;
        }

        private void ValidateAddress(string developmentEmailAddress)
        {
            if (string.IsNullOrEmpty(developmentEmailAddress))
            {
                throw new ArgumentException("Development address cannot be null or empty.");
            }
        }

        private string CreateBody(string subject, string body, IEnumerable<string> toEmailAddresses, IEnumerable<string> ccEmailAddresses)
        {
            string header1 = "The email below was addressed to " + string.Join(", ", toEmailAddresses.ToArray()) + "<br/>";
            string header2 = "\tFollowing users received a CC of the email: " + string.Join(", ", ccEmailAddresses.ToArray()) + "<br/>";
            string originalSubject = "Original subject: " + subject + "<br/>";
            string containedBody = "The body of the email message: <br/><br/>" + body;
            return header1 + header2 + originalSubject + containedBody;
        }
    }

}
